﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Security;
using System.Windows;

using PasswordProvider.ObjectModel;
using PasswordProvider.ViewModel.Properties;
using PasswordProvider.ViewModel.Framework;
using System.Globalization;

namespace PasswordProvider.ViewModel
{
    public class SetPasswordViewModel : VisualViewModel, IRequestClose
    {
        #region Fields, Construction

        private const int _minimumPasswordLength = 3;
        private const int _minimumIterations = 5000;
        
        private string _newFilePath;

        internal SetPasswordViewModel()
            : base(Strings.SetPassword_DisplayName, Strings.SetPassword_ToolTip)
        {            
        }

        internal SetPasswordViewModel(string newFilePath)
            : base(Strings.SetPassword_DisplayName, Strings.SetPassword_ToolTip)
        {
            _newFilePath = newFilePath;
        }
        
        #endregion

        #region ICompleteTask Members

        public event EventHandler CloseRequested;

        #endregion

        #region Public Interface

        public VisualViewModel FirstTimeMessage
        {
            get
            {
                if (_firstTimeMessage == null)
                {
                    _firstTimeMessage = new VisualViewModel(
                        Strings.SetPassword_FirstTime_DisplayString,
                        _newFilePath == null ? Visibility.Collapsed : Visibility.Visible);
                }
                return _firstTimeMessage;
            }
        
        } private VisualViewModel _firstTimeMessage;

        /// <summary>
        /// The main password
        /// </summary>
        public PasswordEntryViewModel PasswordMain
        {
            get
            {
                if (_passwordMain == null)
                {
                    _passwordMain = new PasswordEntryViewModel(Strings.SetPassword_Password_DisplayString);
                    _passwordMain.PasswordChanged +=
                        delegate 
                        { 
                            PasswordVerify.IsEnabled = (_passwordMain.Password.Length >= _minimumPasswordLength);
                            Error = ValidatePasswordMain();
                        };
                }
                return _passwordMain;
            }

        } private PasswordEntryViewModel _passwordMain;

        /// <summary>
        /// The password used to verify that the user typed correctly.
        /// </summary>
        public PasswordEntryViewModel PasswordVerify
        {
            get 
            {
                if (_passwordVerify == null)
                {
                    _passwordVerify = new PasswordEntryViewModel();
                    _passwordVerify.IsEnabled = false;
                    _passwordVerify.PasswordChanged +=
                        delegate
                        {
                            Error = ValidatePasswordVerify();
                        };
                }
                return _passwordVerify; 
            }
        } private PasswordEntryViewModel _passwordVerify;

        /// <summary>
        /// Number of iterations for encryption alg.
        /// </summary>
        public TextEditViewModel NumberOfIterations
        {
            get 
            {
                if (_numberOfIterations == null)
                {
                    int iterations = PasswordProviderData.Current != null ? 
                        PasswordProviderData.Current.MasterKeyGenerationIterations : 20000;
                    
                    _numberOfIterations = new TextEditViewModel(
                        Strings.SetPassword_Iterations_DisplayString,
                        Strings.SetPassword_Iterations_ToolTip,
                        Convert.ToString(iterations, CultureInfo.CurrentCulture));
                    _numberOfIterations.TextValueChanged +=
                        delegate
                        {
                            Error = ValidateNumberOfIterations();
                        };
                }
                return _numberOfIterations; 
            }
        } TextEditViewModel _numberOfIterations; 

        /// <summary>
        /// Apply command.
        /// </summary>
        public CommandViewModel ApplyCommand
        {
            get
            {
                if (_applyCommand == null)
                {
                    _applyCommand = new CommandViewModel(
                        Strings.SetPassword_Apply_DisplayString,
                        Strings.SetPassword_Apply_ToolTip,
                        true,
                        new RelayCommand(param => ApplyCommandExecuted(), param => ApplyCommandCanExecute() ));
                }
                return _applyCommand;
            }
        } CommandViewModel _applyCommand;

        /// <summary>
        /// Error
        /// </summary>
        public string Error
        {
            get {  return _error; }
            set { SetPropertyValue(value, ref _error, "Error"); }
        } private string _error;

        #endregion // Public Interface

        #region Private
        
        private void ApplyCommandExecuted()
        {
            int numIterations = Int32.Parse(NumberOfIterations.Text, CultureInfo.InvariantCulture);

            if (_newFilePath == null)
            {
                PasswordProviderData.Current.ChangePassword(new ProtectedString(PasswordMain.Password), numIterations);
            }
            else
            {
                PasswordProviderData.New(new ProtectedString(PasswordMain.Password), numIterations, _newFilePath);
            }

            if(CloseRequested != null)
                CloseRequested(this, new EventArgs());
        }

        private bool ApplyCommandCanExecute()
        {
            return (CheckAllErrorConditions() == null);
        }
        
        #endregion // Private

        #region Validation
       
        private string CheckAllErrorConditions()
        {
            string[] properties =
            {
                "PasswordMain", "PasswordVerify", "NumberOfIterations"
            };

            foreach (string property in properties)
            {
                string error = GetValidationError(property);
                if (error != null)
                    return error;
            }

            return null;
        }

        private string GetValidationError(string propertyName)
        {
            switch (propertyName)
            {
                case "PasswordMain":
                    return ValidatePasswordMain();
                case "PasswordVerify":
                    return ValidatePasswordVerify();
                case "NumberOfIterations":
                    return ValidateNumberOfIterations();
                 default:
                    return null;
            }
        }

        private string ValidatePasswordMain()
        {
            if (PasswordMain != null && PasswordMain.Password.Length < _minimumPasswordLength)
                return Strings.SetPassword_PasswordLengthError;

            return null;
        }
        private string ValidatePasswordVerify()
        {
            ProtectedString main = new ProtectedString(PasswordMain.Password);
            ProtectedString verify = new ProtectedString(PasswordVerify.Password);

            if (main.UnprotectedString != verify.UnprotectedString)
                return Strings.SetPassword_PasswordMatchError;
            return null;
        }
        private string ValidateNumberOfIterations()
        {
            int value;
            if (!Int32.TryParse(NumberOfIterations.Text, out value))
                return Strings.SetPassword_IterationNotNumberError;

            if (value < _minimumIterations)
                return String.Format(CultureInfo.CurrentCulture, Strings.SetPassword_InterationCountError, _minimumIterations);
            return null;
        }


        #endregion // Private
        
    }
}
